#!/bin/sh

K8S_EKS_NAME="${K8S_EKS_NAME:-stackgres-e2e}"
K8S_EKS_REGION="${K8S_EKS_REGION:-us-west-2}"
K8S_EKS_NODE_TYPE="${K8S_EKS_NODE_TYPE:-m5.large}"
K8S_EKS_NODES="${K8S_EKS_NODES:-1}"
K8S_EKS_DISK_SIZE="${K8S_EKS_DISK_SIZE:-20}"
K8S_EKS_USE_SPOT="${K8S_EKS_USE_SPOT:-true}"
K8S_EKS_OPTS="$K8S_EKS_OPTS"
EKSCTL=eksctl
EKSCTL_0_210_0=eksctl-0.210.0
EKS_EXPANDABLE_STORAGE_CLASSNAME="${EXPANDABLE_STORAGE_CLASSNAME:-expandable-sc}"

export K8S_EKS_NAME K8S_VERSION K8S_EKS_REGION K8S_EKS_NODE_LOCATIONS K8S_EKS_NODE_TYPE K8S_EKS_OPTS

get_k8s_env_version() {
  echo "eksctl version $(eksctl version)"
  echo
}

check_eks_version() {
  if [ "$(echo "$K8S_VERSION" | tr . '\n' | head -n 2 | xargs -I @ printf '%05d' @)" \
      -ge "$(echo "1.31" | tr . '\n' | xargs -I @ printf '%05d' @)" ]
  then
    if ! "$EKSCTL" version | grep -q -F '0.210.0'
    then
      EKSCTL="$EKSCTL_0_210_0"
    fi
    if ! "$EKSCTL" version | grep -q -F '0.210.0'
    then
      echo "$PATH"
      echo "To run Kubernetes 1.31+ eksctl 0.210.0 is required"
      return 1
    fi
  else
    if ! command -v "$EKSCTL" > /dev/null
    then
      return 1
    fi
  fi
}

reuse_k8s() {
  check_eks_version
  if ! eksctl get cluster --name "$K8S_EKS_NAME" --region "$K8S_EKS_REGION" 2>&1 \
    | grep "^$K8S_EKS_NAME" | grep -q "ACTIVE"
  then
    echo "Can not reuse eks environment $K8S_EKS_NAME"
    reset_k8s
    return
  fi

  echo "Reusing eks environment $K8S_EKS_NAME"

  aws eks update-kubeconfig --name "$K8S_EKS_NAME" --region "$K8S_EKS_REGION"

  config_k8s
}

config_k8s() {
  eksctl utils associate-iam-oidc-provider --region="$K8S_EKS_REGION" --cluster="$K8S_EKS_NAME" --approve
  eksctl create iamserviceaccount \
      --region "$K8S_EKS_REGION" \
      --name ebs-csi-controller-sa \
      --namespace kube-system \
      --cluster "$K8S_EKS_NAME" \
      --attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy \
      --approve \
      --role-only \
      --role-name AmazonEKS_EBS_CSI_DriverRole || true
  eksctl create addon --name aws-ebs-csi-driver \
      --region="$K8S_EKS_REGION" \
      --cluster="$K8S_EKS_NAME" \
      --service-account-role-arn arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):role/AmazonEKS_EBS_CSI_DriverRole \
      --force || true
  eksctl update addon --name aws-ebs-csi-driver \
      --region="$K8S_EKS_REGION" \
      --cluster="$K8S_EKS_NAME" \
      --service-account-role-arn arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):role/AmazonEKS_EBS_CSI_DriverRole \
      --force || true

  kubectl create sa cluster-admin-fast 2>/dev/null || true
  kubectl create clusterrolebinding cluster-admin-fast --clusterrole=cluster-admin --serviceaccount=default:cluster-admin-fast 2>/dev/null || true
  if ! SECRET="$(kubectl get sa cluster-admin-fast -o json | jq -r '.secrets[].name' 2>/dev/null)"
  then
    SECRET=cluster-admin-fast
    cat << EOF | kubectl create -f - 2>/dev/null || kubectl get secret cluster-admin-fast > /dev/null
apiVersion: v1
kind: Secret
metadata:
  name: cluster-admin-fast
  annotations:
    kubernetes.io/service-account.name: cluster-admin-fast
type: kubernetes.io/service-account-token
EOF
  fi    
  kubectl get secret "$SECRET" -o json | jq -r '.data["ca.crt"]' | base64 -d > "$TARGET_PATH/eks-ca.crt"
  USER_TOKEN=$(kubectl get secret "$SECRET" -o json | jq -r '.data["token"]' | base64 -d)
  CURRENT_CONTEXT="$(kubectl config current-context)"
  CURRENT_CONTEXT_CLUSTER="$(kubectl config get-contexts "$CURRENT_CONTEXT" | tail -n +2 | tr -s ' \t' ' ' | cut -d ' ' -f 3 | tail -n 1)"
  CURRENT_CONTEXT_ENDPOINT="$(kubectl config view -o jsonpath="{.clusters[?(@.name == \"$CURRENT_CONTEXT_CLUSTER\")].cluster.server}")"
  kubectl config delete-cluster "$CURRENT_CONTEXT_CLUSTER-fast" 2>/dev/null || true
  kubectl config set-cluster "$CURRENT_CONTEXT_CLUSTER-fast" \
    --embed-certs=true \
    --server="$CURRENT_CONTEXT_ENDPOINT" \
    --certificate-authority="$TARGET_PATH/eks-ca.crt"
  kubectl config delete-user "$CURRENT_CONTEXT-fast" 2>/dev/null || true
  kubectl config set-credentials "$CURRENT_CONTEXT-fast" \
    --token="$USER_TOKEN"
  kubectl config set-context "$CURRENT_CONTEXT-fast" \
    --cluster="$CURRENT_CONTEXT_CLUSTER-fast" \
    --user="$CURRENT_CONTEXT-fast" \
    --namespace=default
  kubectl config use-context "$CURRENT_CONTEXT-fast"
}

reset_k8s() {
  check_eks_version

  echo "Setting up eks environment $K8S_EKS_NAME..."

  delete_k8s

  eksctl create cluster --name "$K8S_EKS_NAME" \
    $([ "$K8S_EKS_USE_SPOT" != true ] || printf %s --spot) \
    --region "$K8S_EKS_REGION" \
    --node-type "$K8S_EKS_NODE_TYPE" \
    --node-volume-size "$K8S_EKS_DISK_SIZE" \
    --nodes "$K8S_EKS_NODES" \
    --version "$(printf %s "$K8S_VERSION" | cut -d . -f 1-2)" \
    $K8S_EKS_OPTS
  
  config_k8s

  echo "...done"
}

delete_k8s() {
  check_eks_version

  echo "Checking if eks environment $K8S_EKS_NAME exists"

  if eksctl get cluster --name "$K8S_EKS_NAME" --region "$K8S_EKS_REGION" 2>&1 \
    | grep "^$K8S_EKS_NAME" | grep -q "ACTIVE"
  then
    echo "EKS environment $K8S_EKS_NAME detected, deleteing..."
    eksctl delete cluster --wait --name "$K8S_EKS_NAME" --region "$K8S_EKS_REGION" || true
  else
    echo "EKS environment $K8S_EKS_NAME not detected"
  fi
  
  echo "Cleaning volumes related to the $K8S_EKS_NAME cluster"
  aws ec2 describe-volumes --region "$K8S_EKS_REGION" --filters "Name=tag-key,Values=kubernetes.io/cluster/$K8S_EKS_NAME" \
    | jq -r '.Volumes[].VolumeId' | xargs -r -I % sh -c "aws ec2 detach-volume --force --region $K8S_EKS_REGION --volume-id % || true"
  
  aws ec2 describe-volumes --region "$K8S_EKS_REGION" --filters "Name=tag-key,Values=kubernetes.io/cluster/$K8S_EKS_NAME" \
    | jq -r '.Volumes[].VolumeId' | xargs -r -I % sh -c "aws ec2 delete-volume --region $K8S_EKS_REGION --volume-id % || true" 

  echo "...done"
}

load_image_k8s() {
  echo "Cannot load images directly to k8s in a eks environment"
  exit 1
}

get_k8s_versions() {
  cat << EOF
1.16.8
1.15.11
1.14.9
1.13.12
EOF
}

excluded_validatingwebhookconfigurations() {
  echo "vpc-resource-validating-webhook"
}

excluded_mutatingwebhookconfigurations() {
  echo "pod-identity-webhook"
  echo "vpc-resource-mutating-webhook"
}

excluded_customresourcedefinitions() {
  echo ".*\.amazonaws\.com"
  echo ".*\.k8s\.aws"
}

excluded_podsecuritypolicies() {
  echo "eks\.privileged"
}

excluded_clusterroles() {
  echo "aws-node"
  echo "eks:.*"
  echo "vpc-resource-controller-role"
  echo "ebs-.*"
}

excluded_clusterrolebindings() {
  echo "aws-node"
  echo "eks:.*"
  echo "vpc-resource-controller-rolebinding"
  echo "metrics-server:system:auth-delegator"
  echo "ebs-.*"
}


get_eks_storage_class_name() {
  kubectl get storageclasses.storage.k8s.io \
      -o custom-columns=NAME:.metadata.name,IS_DEFAULT:".metadata.annotations.storageclass\.kubernetes\.io/is-default-class" \
      | awk '{ if ($2 == "true") { print } }' \
      | awk '{print $1}' \
      | head -n +1
}

create_expandable_storage_class_k8s() {
  local DEFAULT_STORAGE_CLASSNAME
  DEFAULT_STORAGE_CLASSNAME="$(get_eks_storage_class_name)"
  generate_expandable_storage_class_from \
    "$DEFAULT_STORAGE_CLASSNAME" \
    "$EKS_EXPANDABLE_STORAGE_CLASSNAME" \
    | kubectl apply -f - > /dev/null
  printf '%s' "$EKS_EXPANDABLE_STORAGE_CLASSNAME"
}
